from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.threads import deferToThread
from twisted.python.failure import Failure
from twisted.python import context
from twisted.web.resource import Resource
from twisted.web.server import NOT_DONE_YET
from littlesite.async_file import AsyncFile


class AbstractResponse:
    def render(self):
        raise NotImplementedError()


class TextResponse(AbstractResponse):
    def __init__(self, text):
        self.text = text

    def render(self):
        return self.text


class HtmlResponse(AbstractResponse):
    def __init__(self, template, model=None):
        self.template = template
        if model is None:
            self.model = {}
        else:
            self.model = model

    @inlineCallbacks
    def render(self):
        file = AsyncFile('resources/%s' % self.template)
        tpl = yield file.read()
        returnValue(tpl % self.model)


class Response(HtmlResponse):
    def render(self):
        return deferToThread(self._render)

    def _render(self):
        tpl = context.get('domain').get_template(self.template)
        result = str(tpl.evoque(self.model))
        return result


class LeafResource(Resource):
    isLeaf = True

    @inlineCallbacks
    def handle(self, request, method):
        try:
            ctx = {'resource': self, 'request': request}
            response = yield context.call(ctx, method, request)
            html = yield response.render()
            request.write(html)
            request.finish()
        except Exception, e:
            request.processingFailed(Failure(e))

    def render_GET(self, request):
        self.handle(request, self.doGet)
        return NOT_DONE_YET

    def doGet(self, request):
        raise NotImplementedError()
